import 'package:flutter_menu/data/obx_store.dart';
import 'package:objectbox/objectbox.dart';
import 'package:json_annotation/json_annotation.dart';

import '../objectbox.g.dart';

part 'product_model.g.dart';

@Entity()
@JsonSerializable()
class ProductModel with IEntity{
  @Id()
  int obxId;

  ///分类id（当为套餐时，categoryId = 0，可通过这个判断是否是套餐）
  String? categoryId;

  ///分类名称
  String? categoryName;

  ///菜品备注
  String? desc;

  ///套餐分组信息
  @JsonKey(fromJson: Group.toManyFromJson, toJson: Group.toManyJson)
  ToMany<Group> groups = ToMany<Group>();

  ///菜品/套餐服务端主键
  @Index()
  String? id;

  ///菜品图片
  String? imageUrl;

  ///是否为套餐菜品（0：默认，1：仅套餐售卖）
  @Deprecated("使用 categoryId 判断")
  int isBundle;

  ///仓库Id
  String? deptId;

  ///菜品/套餐名称
  String? name;

  /////套餐价格/商品零售价
  int? price;

  ///第二语言
  String? secondName;

  ///排序
  int? sort;

  ///规格列表  （套餐类型自身无规格）
  @JsonKey(fromJson: Spec.toManyFromJson, toJson: Spec.toManyJson)
  ToMany<Spec> specs = ToMany<Spec>();

  ///套餐供应时段（只有是套餐才有此字段）
  @JsonKey(
      fromJson: ProductListSupplyTime.toManyFromJson,
      toJson: ProductListSupplyTime.toManyJson)
  ToMany<ProductListSupplyTime> supplyTime = ToMany<ProductListSupplyTime>();

  ///0 菜品或套餐  1 商品或包装
  @Deprecated("使用 categoryId 判断")
  int? type;

  ///是否折扣 0.不折扣 1.折扣
  int? isDiscount;

  ///次字段是[Food]中[fluctuation] 字段的映射，
  ///变价 当是可选套餐时，在原始价格上加上此价格
  @Transient()
  double? fluctuation;

  ProductModel({
    this.obxId = 0,
    this.updateTime =0,
    this.categoryId,
    this.categoryName,
    this.desc,
    this.id,
    this.imageUrl,
    this.deptId,
    this.isBundle = 0,
    this.name,
    this.price,
    this.secondName,
    this.sort,
    this.type,
    this.isDiscount,
  });

  factory ProductModel.fromJson(Map<String, dynamic> json) =>
      _$ProductModelFromJson(json);

  Map<String, dynamic> toJson() => _$ProductModelToJson(this);

  static ToOne<ProductModel> toOneFromJson(Map<String, dynamic> json) =>
      ToOne(target: ProductModel.fromJson(json));

  static Map<String, dynamic>? toOneJson(ToOne<ProductModel> s) =>
      s.target != null ? _$ProductModelToJson(s.target!) : {};

  static ToMany<ProductModel> toManyFromJson(List<dynamic>? json) =>
      ToMany(items: json?.map((e) => ProductModel.fromJson(e)).toList());

  static List<Map<String, dynamic>>? toManyJson(ToMany<ProductModel>? s) =>
      s?.toList().map((e) => e.toJson()).toList();

  @override
  int updateTime;

  @override
  int update(Store store, int? time) {
    updateTime = time?? updateTime;
    groups.forEach((e)=> e.obxId = e.update(store,time));
    specs.forEach((e)=> e.obxId = e.update(store,time));
    supplyTime.forEach((e)=> e.obxId = e.update(store,time));
    var box =  store.box<ProductModel>();
    return box.update(this, ProductModel_.id, id);

  }

  @override
  String toString() {
    return 'ProductModel{obxId: $obxId, id: $id, name: $name, price: $price, secondName: $secondName, sort: $sort, specs: $specs, type: $type, deptId: $deptId}';
  }

  bool isPackage() {
    return categoryId == "0";
  }
}

@Entity()
@JsonSerializable()
class Group with IEntity {
  @Id()
  int obxId;

  ///分组菜品列表
  @JsonKey(fromJson: Food.toManyFromJson, toJson: Food.toManyJson)
  ToMany<Food> foods = ToMany<Food>();

  ///主键id
  @Index()
  String? id;

  ///最大可选数量
  int max;

  ///套餐分组名称
  String? name;

  ///套餐分组第二名称
  String? secondName;

  ///排序字段
  int? sort;

  ///0可选，1固定
  int type;

  Group({
    this.obxId = 0,
    this.updateTime =0,
    this.id,
    this.max = 0,
    this.name,
    this.secondName,
    this.sort,
    this.type = 0,
  });

  factory Group.fromJson(Map<String, dynamic> json) => _$GroupFromJson(json);

  Map<String, dynamic> toJson() => _$GroupToJson(this);

  static ToOne<Group> toOneFromJson(Map<String, dynamic> json) =>
      ToOne(target: Group.fromJson(json));

  static Map<String, dynamic>? toOneJson(ToOne<Group> s) =>
      s.target != null ? _$GroupToJson(s.target!) : {};

  static ToMany<Group> toManyFromJson(List<dynamic>? json) =>
      ToMany(items: json?.map((e) => Group.fromJson(e)).toList());

  static List<Map<String, dynamic>>? toManyJson(ToMany<Group>? s) =>
      s?.toList().map((e) => e.toJson()).toList();

  @override
  int updateTime;

  @override
  int update(Store store, int? time) {
    updateTime = time?? updateTime;
    foods.forEach((e)=> e.obxId = e.update(store,time));
    var box =  store.box<Group>();
    return box.update(this, Group_.id, id);
  }

  bool isFix() {
    return type == 1;
  }
}

@Entity()
@JsonSerializable()
class Food with IEntity{
  @Id()
  int obxId;

  ///套餐菜品id 供线上点单使用
  int? bundleProductId;

  ///价格波动
  double? fluctuation;

  ///菜品id
  String? productId;

  ///份数
  int? quantity;

  ///排序字段
  int? sort;

  ///规格id
  String? specsId;

  Food({
    this.obxId = 0,
    this.updateTime= 0,
    this.bundleProductId,
    this.fluctuation,
    this.productId,
    this.quantity,
    this.sort,
    this.specsId,
  });

  factory Food.fromJson(Map<String, dynamic> json) => _$FoodFromJson(json);

  Map<String, dynamic> toJson() => _$FoodToJson(this);

  static ToOne<Food> toOneFromJson(Map<String, dynamic> json) =>
      ToOne(target: Food.fromJson(json));

  static Map<String, dynamic>? toOneJson(ToOne<Food> s) =>
      s.target != null ? _$FoodToJson(s.target!) : {};

  static ToMany<Food> toManyFromJson(List<dynamic>? json) =>
      ToMany(items: json?.map((e) => Food.fromJson(e)).toList());

  static List<Map<String, dynamic>>? toManyJson(ToMany<Food>? s) =>
      s?.toList().map((e) => e.toJson()).toList();

  @override
  int updateTime;

  @override
  int update(Store store, int? time) {
   updateTime = time?? updateTime;
   var box =  store.box<Food>();
   return box.put(this);
  }

  @override
  String toString() {
    return 'Food{obxId: $obxId, bundleProductId: $bundleProductId, fluctuation: $fluctuation, productId: $productId, quantity: $quantity, sort: $sort, specsId: $specsId}';
  }
}

@Entity()
@JsonSerializable()
class Spec  with IEntity{
  @Id()
  int obxId;

  ///成本价
  double costPrice;

  ///计数
  double? counting;

  ///规格id
  @Index()
  String? id;

  ///时价  0 否 1 是
  int isCurrentPrice;

  ///是否默认 0 未选中 1 选中
  int isDefault;

  ///是否允许折扣 0否 1是
  int isDiscountEnable;

  ///是否停售（0否 1是）
  int isStop;

  ///是否称重（0否 1是）
  String? isWeight;

  ///规格名称
  String? name;

  ///选项集合
  @JsonKey(fromJson: SpecOption.toManyFromJson, toJson: SpecOption.toManyJson)
  ToMany<SpecOption> options = ToMany<SpecOption>();

  ///规格售价
  double? price;

  ///起点数量
  double? reserveMin;

  ///第二语言
  String? secondName;

  ///排序字段
  int? sort;

  Spec({
    this.obxId = 0,
    this.costPrice = 0,
    this.updateTime=0,
    this.counting,
    this.id,
    this.isCurrentPrice = 0,
    this.isDefault = 0,
    this.isDiscountEnable = 0,
    this.isStop = 0,
    this.isWeight,
    this.name,
    this.price,
    this.reserveMin,
    this.secondName,
    this.sort,
  });

  factory Spec.fromJson(Map<String, dynamic> json) => _$SpecFromJson(json);

  Map<String, dynamic> toJson() => _$SpecToJson(this);

  static ToOne<Spec> toOneFromJson(Map<String, dynamic> json) =>
      ToOne(target: Spec.fromJson(json));

  static Map<String, dynamic>? toOneJson(ToOne<Spec> s) =>
      s.target != null ? _$SpecToJson(s.target!) : {};

  static ToMany<Spec> toManyFromJson(List<dynamic>? json) =>
      ToMany(items: json?.map((e) => Spec.fromJson(e)).toList());

  static List<Map<String, dynamic>>? toManyJson(ToMany<Spec>? s) =>
      s?.toList().map((e) => e.toJson()).toList();

  @override
  int updateTime;

  @override
  int update(Store store, int? time) {
    updateTime = time?? updateTime;
    options.forEach((e)=> e.obxId = e.update(store,time));
    var box =  store.box<Spec>();
    return box.update(this, Spec_.id, id);
  }

  @override
  String toString() {
    return 'Spec{counting: $counting, id: $id, isDefault: $isDefault, isStop: $isStop, name: $name, options: $options, price: $price, sort: $sort}';
  }

  bool isDefaultSpec() {
    return isDefault == 1;
  }

  bool isStopSpec() {
    return isStop == 1;
  }
}

@Entity()
@JsonSerializable()
class SpecOption with IEntity{
  @Id()
  int obxId;

  ///id
  @Index()
  String? id;

  ///是否默认
  int isDefault;

  ///最大可选数量
  int maxQty;

  ///选项名
  String? name;

  @JsonKey(fromJson: SpecOption.toManyFromJson, toJson: SpecOption.toManyJson)
  ToMany<SpecOption> options = ToMany<SpecOption>();

  ///选项组id
  int? optionsGroupId;

  ///选项组名称
  String? optionsGroupName;

  ///选项组第二名称
  String? optionsGroupSecondName;

  ///price
  int? price;

  ///菜品uuid
  String? productId;

  ///选项第二名称
  String? secondName;

  ///排序字段
  int? sort;

  ///规格uuid
  String? specsId;

  ///0 单个单选  1、多个互斥  2、多个多选
  int type;

  SpecOption({
    this.obxId = 0,
    this.updateTime = 0,
    this.id,
    this.isDefault = 0,
    this.maxQty = 1,
    this.name,
    this.optionsGroupId,
    this.optionsGroupName,
    this.optionsGroupSecondName,
    this.price,
    this.productId,
    this.secondName,
    this.sort,
    this.specsId,
    this.type = 0,
  });

  factory SpecOption.fromJson(Map<String, dynamic> json) =>
      _$SpecOptionFromJson(json);

  Map<String, dynamic> toJson() => _$SpecOptionToJson(this);

  static ToOne<SpecOption> toOneFromJson(Map<String, dynamic> json) =>
      ToOne(target: SpecOption.fromJson(json));

  static Map<String, dynamic>? toOneJson(ToOne<SpecOption> s) =>
      s.target != null ? _$SpecOptionToJson(s.target!) : {};

  static ToMany<SpecOption> toManyFromJson(List<dynamic>? json) =>
      ToMany(items: json?.map((e) => SpecOption.fromJson(e)).toList());

  static List<Map<String, dynamic>>? toManyJson(ToMany<SpecOption>? s) =>
      s?.toList().map((e) => e.toJson()).toList();

  @override
  int updateTime;

  @override
  int update(Store store, int? time) {
    updateTime = time?? updateTime;
    options.forEach((e)=> e.obxId = e.update(store,time));
    var box =  store.box<SpecOption>();
    return box.update(this, SpecOption_.id, id);
  }

  bool isDefaultOption() {
    return isDefault == 1;
  }

  String getNameWithPrice() {
    if ((price ?? 0) > 0 && (name != null)) {
      return "$name+$price";
    }
    return name ?? "";
  }

  bool isGroupOption() {
    return optionsGroupName?.isNotEmpty == true && options.isNotEmpty;
  }


  @override
  String toString() {
    return 'SpecOption{id: $id, isDefault: $isDefault, options: $options, optionsGroupId: $optionsGroupId, optionsGroupName: $optionsGroupName, price: $price, productId: $productId, sort: $sort, type: $type}';
  }
}

@Entity()
@JsonSerializable()
class ProductListSupplyTime with IEntity{
  @Id()
  int obxId;
  List<int>? days;
  String? marketTypeCode;
  String? marketTypeName;

  ProductListSupplyTime(
      {this.days, this.marketTypeCode, this.marketTypeName, this.obxId = 0,this.updateTime =0});

  factory ProductListSupplyTime.fromJson(Map<String, dynamic> json) =>
      _$ProductListSupplyTimeFromJson(json);

  Map<String, dynamic> toJson() => _$ProductListSupplyTimeToJson(this);

  static ToOne<ProductListSupplyTime> toOneFromJson(
          Map<String, dynamic> json) =>
      ToOne(target: ProductListSupplyTime.fromJson(json));

  static Map<String, dynamic>? toOneJson(ToOne<ProductListSupplyTime> s) =>
      s.target != null ? _$ProductListSupplyTimeToJson(s.target!) : {};

  static ToMany<ProductListSupplyTime> toManyFromJson(List<dynamic>? json) =>
      ToMany(
          items: json?.map((e) => ProductListSupplyTime.fromJson(e)).toList());

  static List<Map<String, dynamic>>? toManyJson(
          ToMany<ProductListSupplyTime>? s) =>
      s?.toList().map((e) => e.toJson()).toList();

  @override
  int updateTime;

  @override
  int update(Store store, int? time) {
    updateTime = time?? updateTime;
    var box =  store.box<ProductListSupplyTime>();
    return box.put(this);
  }
}
